package com.woniu.filter;

import cn.hutool.json.JSONUtil;
import cn.hutool.jwt.JWTUtil;
import com.woniu.dto.UserDto;
import com.woniu.service.SecurityUserDetailsService;
import com.woniu.utils.WebFluxUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.data.redis.core.ReactiveStringRedisTemplate;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.ReactiveSecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebFilter;
import org.springframework.web.server.WebFilterChain;
import reactor.core.publisher.Mono;

import java.time.Duration;

import static com.woniu.constant.Constant.Security.JWT_SECRET_KEY;

@Component
public class JWTokenFilter implements WebFilter {

    @Autowired
    ReactiveStringRedisTemplate redisTemplate;

    @Autowired
    SecurityUserDetailsService userDetailsService;


    @Override
    public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();

        String JWToken = request.getHeaders().getFirst("JWToken");
        if (JWToken == null || !JWTUtil.verify(JWToken, JWT_SECRET_KEY.getBytes())) {
            return WebFluxUtil.JWTokenFailed(exchange);
        }

        UserDto userInfo = JSONUtil.toBean(JWTUtil.parseToken(JWToken).getPayloads(), UserDto.class);

        return redisTemplate.hasKey("JWToken:" + JWToken)
                .flatMap(redisToken -> {
                    /*if (redisToken == null || !redisToken.equals(JWToken)) {
                        return WebFluxUtil.JWTokenFailed(exchange);
                    }*/
                    if (!redisToken) {
                        return WebFluxUtil.JWTokenFailed(exchange);
                    }
                    // jwt续期
                    redisTemplate.expire("JWToken:" + JWToken, Duration.ofMinutes(30)).subscribe();
                    return userDetailsService.findByUsername(userInfo.getUsername())
                            .flatMap(user -> chain.filter(exchange).subscriberContext(ReactiveSecurityContextHolder.withAuthentication(
                                    new UsernamePasswordAuthenticationToken(user.getUsername(), user.getPassword(), user.getAuthorities())
                            )));
                });

    }

}
